package process

import (
	"encoding/json"
	"fmt"
	"go_example/src/chatroom/common/message"
	"go_example/src/chatroom/server/model"
	"go_example/src/chatroom/server/utils"
	"net"
)

type UserProcess struct {
	Conn net.Conn
	UserId int //表示Conn是哪个用户
}


//通知所有用户在线的方法
//userId 要通知其它的在线用户，表示该用户已上线
func (this *UserProcess) NotifyOthersOnlineUser(userId int)  {
	//遍历onlineUsers后一个个发送NotifyUserStatusMes
	for id, up := range userMgr.onlineUsers {
	//for id, up := range userMgr.GetAllOnlineUser() {
		//过滤掉自己
		if id == userId {
			continue
		}
		up.NotifyMeOnline(userId)
	}

}

func (this *UserProcess) NotifyMeOnline(userId int)  {
	//组装消息
	var mes message.Message
	mes.Type = message.NotifyUserStatusMesType

	var notifyUserStatusMes message.NotifyUserStatusMes
	notifyUserStatusMes.UserId = userId
	notifyUserStatusMes.Status = message.UserOnline

	//将notifyUserStatusMes序列化
	data, err := json.Marshal(notifyUserStatusMes)
	if err != nil {
		fmt.Println("NotifyMeOnline() notifyUserStatusMes json.Marshal err=", err)
		return
	}
	//序列化后赋值给mes.Data
	mes.Data = string(data)

	//对mes再次序列化，准备发送
	data, err = json.Marshal(mes)
	if err != nil {
		fmt.Println("NotifyMeOnline() mes json.Marshal err=", err)
		return
	}

	//发送
	tf := &utils.Transfer{
		Conn: this.Conn,
	}
	err = tf.WritePkg(data)
	return
}

//处理注册请求
func (this *UserProcess) ServerProcessRegister(mes *message.Message) (err error) {
	var registerMes message.RegisterMes
	err = json.Unmarshal([]byte(mes.Data), &registerMes)
	if err != nil {
		fmt.Println("ServerProcessRegister() &registerMes json.Unmarshal err=", err)
		return
	}

	var resMes message.Message
	resMes.Type = message.RegisterResMesType
	var registerResMes message.RegisterResMes

	//写入redis的数据库去完成注册，使用model。MyUserDao到redis去验证
	err = model.MyUserDao.Register(&registerMes.User)
	if err != nil {
		if err == model.ErrorUserExists {
			registerResMes.Code = 505
			registerResMes.Error = model.ErrorUserExists.Error()
		} else {
			registerResMes.Code = 506
			registerResMes.Error = "注册发生未知错误"
		}
	} else {
		registerResMes.Code = 200
	}

	//将loginResMes序列化
	data, err := json.Marshal(registerResMes)
	if err != nil {
		fmt.Println("ServerProcessRegister() registerResMes json.Marshal err=", err)
		return
	}
	//将data复制给resMes
	resMes.Data = string(data)

	//对resMes进行序列化，准备发送
	data, err = json.Marshal(resMes)
	if err != nil {
		fmt.Println("ServerProcessRegister() resMes json.Marshal err=", err)
		return
	}
	//发送数据，将其封装到writePkg函数
	//因为使用分层模式（mvc），先创建一个Transfer实例，然后再读取
	tf := &utils.Transfer{
		Conn: this.Conn,
	}
	err = tf.WritePkg(data)
	return
}

//处理登陆请求
func (this *UserProcess) ServerProcessLogin(mes *message.Message) (err error) {
	//核心代码
	//从mes中取出mes.Data，并直接反序列化成loginMes
	var loginMes message.LoginMes
	err = json.Unmarshal([]byte(mes.Data), &loginMes)
	if err != nil {
		fmt.Println("ServerProcessLogin() &loginMes json.Unmarshal err=", err)
		return
	}

	var resMes message.Message
	resMes.Type = message.LoginResMesType

	var loginResMes message.LoginResMes
	//用户登陆通过数据库验证
	user, err := model.MyUserDao.Login(loginMes.UserId, loginMes.UserPwd)
	if err != nil {
		loginResMes.Code = 500 //表示用户不存在
		loginResMes.Error = "该用户不存在，请注册..."
	} else {
		loginResMes.Code = 200
		//因为用户已经登陆成功了，需要把该登陆成功的用户放入到UserMgr中

		//将登陆成功的用户id赋值给this
		this.UserId = loginMes.UserId
		userMgr.AddOnlineUser(this)

		//通知其它在线用户，上线了
		this.NotifyOthersOnlineUser(loginMes.UserId)

		//将当前在线用户的id，放入到loginResMes.UsersIds
		for id, _ := range userMgr.onlineUsers {
			loginResMes.UsersId = append(loginResMes.UsersId, id)
			//遍历维护在线用户的map
			//for  key, value := range userMgr.GetAllOnlineUser() {
			//	fmt.Printf("%d = %s\n", key, value)
			//}
		}

		fmt.Println(user, "登陆成功")
	}

	//将loginResMes序列化
	data, err := json.Marshal(loginResMes)
	if err != nil {
		fmt.Println("ServerProcessLogin() loginResMes json.Marshal err=", err)
		return
	}
	//将data复制给resMes
	resMes.Data = string(data)

	//对resMes进行序列化，准备发送
	data, err = json.Marshal(resMes)
	if err != nil {
		fmt.Println("ServerProcessLogin() resMes json.Marshal err=", err)
		return
	}
	//发送数据，将其封装到writePkg函数
	//因为使用分层模式（mvc），先创建一个Transfer实例，然后再读取
	tf := &utils.Transfer{
		Conn: this.Conn,
	}
	err = tf.WritePkg(data)
	return
}